﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using ThePresenter.IO;
using ThePresenter.Windows;

namespace ThePresenter
{
	/// <summary>
	/// Interaction logic for App.xaml
	/// </summary>
	public partial class App : Application
	{
		#region Fields

		/// <summary>
		/// The application directory.
		/// </summary>
		static readonly string _AppDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		/// <summary>
		/// Stores all instances created by app
		/// </summary>
		private List<ProgramInstance> _Instances;

		#endregion

		#region Properies

		/// <summary>
		/// Gets the <see cref="ThePresenter.App"/> object for the current <see cref="System.AppDomain"/>.
		/// </summary>
		/// <value>The <see cref="ThePresenter.App"/> object for the current <see cref="System.AppDomain"/>.</value>
		public static new App Current
		{
			get
			{
				return Application.Current as App;
			}
		}

		/// <summary>
		/// Gets the application directory.
		/// </summary>
		/// <value>The application directory.</value>
		public static string AppDirectory
		{
			get
			{
				return _AppDirectory;
			}
		}

		#endregion

		#region Constructors

		/// <summary>
		/// Initializes the <see cref="App"/> class.
		/// </summary>
		/// <exception cref="T:System.InvalidOperationException">More than one instance of the <see cref="T:System.Windows.Application"/> class is created per <see cref="T:System.AppDomain"/>.</exception>
		static App()
		{
			Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
		}

		#endregion

		#region Methods

		/// <summary>
		/// Handles the Startup event of the Application control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.StartupEventArgs"/> instance containing the event data.</param>
		private void Application_Startup(object sender, StartupEventArgs e)
		{
			ShutdownMode = ShutdownMode.OnExplicitShutdown;
			_Instances = new List<ProgramInstance>();

			string[] args = Environment.GetCommandLineArgs();

			if (args.Length > 1)
			{
				if (args.Contains("-network")) // HACK NetworkDebug
				{
					ProgramInstance PI;
					PI = new ProgramInstance("Presenter");
					PI.Start(StartupMode.Presenter);
					_Instances.Add(PI);

					PI = new ProgramInstance("Watcher");
					PI.Start(StartupMode.Watcher);
					_Instances.Add(PI);
				}
				else
				{
					if (args.Contains("-h")) // help
					{
						MessageBox.Show("Usage: -spwrh\r\n  -s Standalone mode,\r\n  -p Presenter mode,\r\n  -w Watcher mode,\r\n  -r RemoteProjector mode,\r\n  -h Help.", "Help", MessageBoxButton.OK, MessageBoxImage.Information);
					}
					else
					{
						Stack<String> Args = new Stack<string>(args);

						StartupMode SM;
						ProgramInstance PI;

						while (Args.Count > 0)
						{
							String arg = Args.Pop();
							switch (arg)
							{
								case "-s":
								case "--standalone":
									SM = StartupMode.Standalone;
									break;
								case "-p":
								case "--presenter":
									SM = StartupMode.Presenter;
									break;
								case "-w":
								case "--watcher":
									SM = StartupMode.Watcher;
									break;
								case "-r":
								case "--remote":
									SM = StartupMode.RemoteProjector;
									break;
								default:
									continue;
							}

							PI = new ProgramInstance(String.Format("Instance #{0} ({1})", _Instances.Count + 1, SM));
							_Instances.Add(PI);
							PI.Start(SM);
						}
					}
				}
			}
			else // start normally
			{
				var PI = new ProgramInstance("Main Program");

				_Instances.Add(PI);
#if DEBUG
				PI.Start(StartupMode.Prompt);
#else
				PI.Start(StartupMode.Prompt);
#endif
			}

			if (Application.Current.Windows.Count > 0)
			{
				ShutdownMode = ShutdownMode.OnLastWindowClose;
			}
			else
			{
				Application.Current.Shutdown();
			}
		}

		/// <summary>
		/// Handles the Exit event of the Application control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.ExitEventArgs"/> instance containing the event data.</param>
		private void Application_Exit(object sender, ExitEventArgs e)
		{
			Environment.Exit(e.ApplicationExitCode);
		}

		/// <summary>
		/// Handles the DispatcherUnhandledException event of the Application control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Threading.DispatcherUnhandledExceptionEventArgs"/> instance containing the event data.</param>
		private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
		{
			var ex = e.Exception;

			if (ex != null)
			{
#if DEBUG
				// Rethrow back
				throw ex;
#else
				// Format error message text
				var msg = string.Format("{0}:\r\n{1}", ex.GetType().FullName, ex.ToString());

				// Show error message to client
				MessageBox.Show(msg, "Unhandled exception.", MessageBoxButton.OK, MessageBoxImage.Error);

				// Prevent default unhandled exception processing
				e.Handled = true;
#endif
			}
		}

		#endregion

		#region Classes

		/// <summary>
		/// Input/Output subclass.
		/// </summary>
		public static class IO
		{
			#region Properties

			/// <summary>
			/// Gets the list of possible readers.
			/// </summary>
			public static readonly List<IReader> Readers = new List<IReader>() { new Ppt(), new Pptx(), new Xaml() };

			/// <summary>
			/// Gets the list of possible writers.
			/// </summary>
			public static readonly List<IWriter> Writers = new List<IWriter>() { new Pdf(), new Xps(), new Xaml() };

			#endregion
		}

		#endregion
	}
}
